package controllers

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v4"
	"gorm.io/gorm"
	"io"
	"log"
	"partyus_app/cos_api"
	"partyus_app/global"
	"partyus_app/models"
	"partyus_app/response"
	"partyus_app/utils"
	_ "path/filepath"
	"strconv"
)

// PublishPost 处理函数
func PublishPost(ctx *gin.Context) {
	var req struct {
		Video   string `json:"video"`
		Title   string `json:"title" binding:"required"`
		Content string `json:"content" binding:"required"`
		Part    *int   `json:"part" binding:"required,oneof=0 1 2 3 4 5"`
		Cover   string `json:"cover"`
	}

	// 绑定并验证请求参数
	if err := ctx.Bind(&req); err != nil {
		response.CommonResp(ctx, 1, "参数错误，或者漏填写必填项", nil)
		return
	}

	userID, ok := ctx.Get("userID")
	if !ok {
		response.CommonResp(ctx, 1, "帖子创建失败", nil)
		return
	}

	//如果上传的是视频并且没有封面
	if req.Video != "" && req.Cover == "" {
		cover, err := utils.ExtractFirstFrameToCOS(req.Video, utils.GenerateHashedFilename(req.Video))
		if err != nil {
			response.CommonResp(ctx, 1, "视频帖子创建解析封面失败", nil)
			return
		}
		req.Cover = cover
	}

	typ := 0
	if req.Video != "" {
		typ = 1
	}
	// 构造帖子对象
	post := models.Post{
		UserID:  userID.(int),
		Type:    typ,
		Title:   req.Title,
		Content: req.Content,
		Part:    *req.Part,
		IsAudit: 0,
		Cover:   req.Cover,
		Video:   req.Video,
	}

	// 将帖子保存到数据库
	if err := global.Db.Create(&post).Error; err != nil {
		response.CommonResp(ctx, 1, "帖子创建失败", nil)
		return
	}

	// 返回成功响应
	response.CommonResp(ctx, 0, "帖子创建成功", nil)
}

func UploadFile(ctx *gin.Context) {
	fileHeader, err := ctx.FormFile("file")
	if err != nil {
		log.Printf(err.Error())
		response.CommonResp(ctx, 1, "文件上传失败", nil)
		return
	}

	filename := fileHeader.Filename
	isImage := utils.IsValidExtension(filename, utils.ImageExtensions)
	isVideo := utils.IsValidExtension(filename, utils.VideoExtensions)

	if !isImage && !isVideo {
		response.CommonResp(ctx, 1, "不支持的文件格式，仅支持图片或视频", nil)
		return
	}

	saveDir := "pictures"
	if isVideo {
		saveDir = "videos"
	}

	hashedFilename := utils.GenerateHashedFilename(filename)
	objectKey := fmt.Sprintf("%s/%s", saveDir, hashedFilename)

	// 打开上传文件流
	file, err := fileHeader.Open()
	if err != nil {
		response.CommonResp(ctx, 1, "文件读取失败", nil)
		return
	}
	defer file.Close()

	var reader io.Reader

	if isImage {
		reader, err = utils.CompressImageToJPEG(file, 75)
		if err != nil {
			// 兜底
			reader = file
		}
	} else {
		// 视频不处理，直接上传
		reader = file
	}

	// 上传到 COS
	fileURL, err := cos_api.UploadReaderToCOS(reader, objectKey)
	if err != nil {
		log.Print(err)
		response.CommonResp(ctx, 1, "上传至 COS 失败", nil)
		return
	}

	res := struct {
		FileUrl string `json:"fileUrl"`
	}{FileUrl: fileURL}
	response.CommonResp(ctx, 0, "上传成功", res)
}

// 更新帖子内容
func UpdatePost(ctx *gin.Context) {
	var req struct {
		PostID  int    `json:"postID"`
		Title   string `json:"title" `
		Content string `json:"content" `
		Part    *int   `json:"part" binding:"oneof=0 1 2 3 4 5"`
		Cover   string `json:"cover"`
		Video   string `json:"video"`
	}
	if err := ctx.Bind(&req); err != nil {
		response.CommonResp(ctx, 1, "参数错误", nil)
		return
	}

	//校验是否是帖子的发帖人
	userID, ok := ctx.Get("userID")
	if !ok {
		response.CommonResp(ctx, 1, "帖子创建失败", nil)
		return
	}
	userID = userID.(int)
	postOld := models.Post{}
	//允许查到软删除帖子
	if err := global.Db.Unscoped().Model(&models.Post{}).Where("id = ?", req.PostID).First(&postOld).Error; err != nil {
		response.CommonResp(ctx, 1, "帖子不存在", nil)
		return
	}
	if postOld.UserID != userID {
		response.CommonResp(ctx, 1, "非法操作", nil)
		return
	}
	if req.Title != "" {
		postOld.Title = req.Title
	}
	if req.Content != "" {
		postOld.Content = req.Content
	}
	if req.Part != nil {
		postOld.Part = *req.Part
	}
	if req.Cover != "" {
		postOld.Cover = req.Cover
	}
	oldVideo := postOld.Video
	if req.Video != "" {
		postOld.Video = req.Video
		// 如果是新视频
		if oldVideo != req.Video {
			cover, err := utils.ExtractFirstFrameToCOS(req.Video, utils.GenerateHashedFilename(req.Video))
			if err != nil {
				response.CommonResp(ctx, 1, "视频帖子创建解析封面失败", nil)
				return
			}
			req.Cover = cover
			postOld.Cover = req.Cover
		}
	}
	postOld.IsAudit = 0

	//更新操作
	if err := global.Db.Save(&postOld).Error; err != nil {
		response.CommonResp(ctx, 1, "更新帖子信息失败", nil)
		return
	}
	response.CommonResp(ctx, 0, "更新帖子成功", nil)
}

// Browse获取帖子流
func Browse(ctx *gin.Context) {
	// 定义请求体结构
	var req struct {
		Part        *int   `json:"part" binding:"required"`     // 分区
		PageNum     int    `json:"pageNum" binding:"required"`  // 页码
		PageSize    int    `json:"pageSize" binding:"required"` // 每页数量
		SearchQuery string `json:"searchQuery" binding:""`      // 搜索关键字，非必填
	}

	var res struct {
		Posts []response.RespPost `json:"posts"`
		Total int64               `json:"total"`
	}

	// 绑定 JSON 数据
	if err := ctx.Bind(&req); err != nil {
		response.CommonResp(ctx, 1, "请求参数错误", nil)
		return
	}

	// 计算分页偏移量
	offset := (req.PageNum - 1) * req.PageSize

	// 构建基础查询
	query := global.Db.Model(&models.Post{}).Preload("User").
		Where("part = ? AND is_audit = ?", req.Part, 1) // 默认只查询已审核的帖子

	// 如果提供了搜索关键字，则进行模糊查询
	if req.SearchQuery != "" {
		searchQuery := "%" + req.SearchQuery + "%" // 拼接 SQL 的模糊查询格式
		query = query.Where("title LIKE ? OR content LIKE ?", searchQuery, searchQuery)
	}

	// 查询总记录数，用于分页（不使用 Offset 和 Limit）
	var total int64
	if err := query.Count(&total).Error; err != nil {
		response.CommonResp(ctx, 1, "查询总记录数失败", nil)
		return
	}

	// 查询数据库中的帖子数据（使用 Offset 和 Limit）
	var posts []models.Post
	if err := query.Offset(offset).Limit(req.PageSize).Order("created_at DESC").Find(&posts).Error; err != nil {
		response.CommonResp(ctx, 1, "查询失败", nil)
		return
	}

	// 截取内容
	utils.CutPostContent(&posts)

	// 配置 URL，处理视频和封面链接
	respPosts := []response.RespPost{}
	for i := range posts {
		respPosts = append(respPosts, response.ToResponsePost(posts[i]))
	}

	// 设置响应数据
	res.Posts = respPosts
	res.Total = total

	// 返回响应
	response.CommonResp(ctx, 0, "查询成功", res)
}

func GetApprovedList(ctx *gin.Context) {
	// 解析查询参数
	partStr := ctx.Query("part")
	part := -1
	if partStr != "" {
		var err error
		part, err = strconv.Atoi(partStr)
		if err != nil || part < 0 {
			response.CommonResp(ctx, 1, "请求参数错误：分区参数无效", nil)
			return
		}
	}

	pageNum, err := strconv.Atoi(ctx.Query("pageNum"))
	if err != nil || pageNum <= 0 {
		response.CommonResp(ctx, 1, "请求参数错误：页码无效", nil)
		return
	}

	pageSize, err := strconv.Atoi(ctx.Query("pageSize"))
	if err != nil || pageSize <= 0 {
		response.CommonResp(ctx, 1, "请求参数错误：分页大小无效", nil)
		return
	}

	isApproved, err := strconv.Atoi(ctx.Query("isApproved"))
	if !(isApproved == 1 || isApproved == 2 || isApproved == 0) {
		response.CommonResp(ctx, 1, "请求参数错误：审批状态无效", nil)
		return
	}

	searchQuery := ctx.Query("searchQuery") // 获取搜索关键词

	var res struct {
		Posts []response.RespPost `json:"posts"`
		Total int64               `json:"total"`
	}

	// 计算分页偏移量
	offset := (pageNum - 1) * pageSize

	// 构建动态查询条件
	query := global.Db.Model(&models.Post{}).Preload("User").Where("is_audit = ?", isApproved)
	if part != -1 {
		query = query.Where("part = ?", part)
	}
	if searchQuery != "" {
		query = query.Where("title LIKE ? OR content LIKE ?", "%"+searchQuery+"%", "%"+searchQuery+"%")
	}

	// 查询帖子数据
	var posts []models.Post
	if err := query.Offset(offset).Limit(pageSize).Find(&posts).Error; err != nil {
		response.CommonResp(ctx, 1, "查询失败", nil)
		return
	}

	// 配置资源 URL
	utils.CutPostContent(&posts)
	respPosts := []response.RespPost{}
	for i := range posts {
		// 截断 content 字段，如果超过 100 字
		//if utf8.RuneCountInString(posts[i].Content) > 100 {
		//	// 获取前 100 个字符
		//	runes := []rune(posts[i].Content)              // 转换为 rune 切片
		//	posts[i].Content = string(runes[:100]) + "..." // 按字符截断，并添加省略号
		//}
		respPosts = append(respPosts, response.ToResponsePost(posts[i]))
	}

	// 查询总记录数（避免分页影响统计）
	var total int64
	countQuery := global.Db.Model(&models.Post{}).Where("is_audit = ?", isApproved)

	if part != -1 {
		countQuery = countQuery.Where("part = ?", part)
	}

	if searchQuery != "" {
		countQuery = countQuery.Where("title LIKE ? OR content LIKE ?", "%"+searchQuery+"%", "%"+searchQuery+"%")
	}

	if err := countQuery.Count(&total).Error; err != nil {
		response.CommonResp(ctx, 1, "查询总记录数失败", nil)
		return
	}
	//utils.CutPostContent(&posts)

	res.Posts = respPosts
	res.Total = total

	// 返回响应
	response.CommonResp(ctx, 0, "查询成功", res)
}

func ApproveAction(ctx *gin.Context) {
	// 定义请求体结构
	var req struct {
		PostID int `json:"postID" binding:"required"`
		Action int `json:"action" binding:"required,oneof=1 2"`
	}

	// 绑定 JSON 数据
	if err := ctx.ShouldBindJSON(&req); err != nil {
		response.CommonResp(ctx, 1, "请求参数错误", nil)
		return
	}

	// 查询帖子是否存在
	var post models.Post
	if err := global.Db.Where("id = ?", req.PostID).First(&post).Error; err != nil {
		response.CommonResp(ctx, 1, "帖子不存在", nil)
		return
	}

	// 更新帖子的审核状态
	newStatus := req.Action

	if post.IsAudit != 0 {
		response.CommonResp(ctx, 1, "非法操作", nil)
		return
	} else if post.IsAudit == newStatus {
		response.CommonResp(ctx, 1, "该帖子已审批", nil)
		return
	}
	post.IsAudit = newStatus

	if err := global.Db.Save(&post).Error; err != nil {
		response.CommonResp(ctx, 1, "审核操作失败", nil)
		return
	}

	response.CommonResp(ctx, 0, "审批成功！", nil)
}

func GetSelfPost(ctx *gin.Context) {
	var resp = struct {
		Posts []response.RespPost `json:"posts"`
		Total int64               `json:"total"`
	}{}

	// 获取用户 ID
	tokenString := ctx.Query("token")
	userID := 0

	// 解析和验证令牌
	token, err := utils.ParseString2Token(tokenString)
	hasToken := true
	if err != nil || !token.Valid {
		hasToken = false
	}

	// 提取 Claims
	if hasToken {
		if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
			// 提取 userID 和 role
			userIDf, ok := claims["ID"].(float64)
			if !ok {
				response.CommonResp(ctx, 1, "token缺少必要信息", nil)
				return
			}
			userID = int(userIDf)
		}
	}

	// 获取请求中的用户 ID (用于特定用户查询)
	reqUserIDStr := ctx.DefaultQuery("userID", "")
	reqUserID := 0
	if reqUserIDStr != "" {
		reqUserID, _ = strconv.Atoi(reqUserIDStr)
	}

	// 获取审核状态
	isAuditStr := ctx.Query("isAudit")
	isAudit, err := strconv.Atoi(isAuditStr)
	if err != nil || (isAudit != 0 && isAudit != 1 && isAudit != 2) {
		// 如果没有传入正确的审核状态，默认值为 1
		response.CommonResp(ctx, 1, "审核状态参数错误", nil)
		return
	}

	if userID != reqUserID {
		isAudit = 1
	}

	// 获取分页参数
	pageNumStr := ctx.Query("pageNum")
	pageSizeStr := ctx.Query("pageSize")

	pageNum, err := strconv.Atoi(pageNumStr)
	if err != nil || pageNum < 1 {
		response.CommonResp(ctx, 1, "分页参数错误：pageNum", nil)
		return
	}

	pageSize, err := strconv.Atoi(pageSizeStr)
	if err != nil || pageSize < 1 {
		response.CommonResp(ctx, 1, "分页参数错误：pageSize", nil)
		return
	}

	// 查询总数
	var total int64
	query := global.Db.Where("is_audit = ?", isAudit)

	query = query.Where("user_id = ?", reqUserID)

	if err = query.Model(&models.Post{}).Count(&total).Error; err != nil {
		response.CommonResp(ctx, 1, "查询失败", nil)
		return
	}

	// 查询分页数据
	var posts []models.Post
	if err = query.Offset((pageNum - 1) * pageSize).
		Limit(pageSize).
		Order("created_at DESC").
		Find(&posts).Error; err != nil {
		response.CommonResp(ctx, 1, "查询失败", nil)
		return
	}
	utils.CutPostContent(&posts)

	// 转换为响应格式
	respPosts := []response.RespPost{}
	for _, p := range posts {
		respPosts = append(respPosts, response.ToResponsePost(p))
	}

	resp.Posts = respPosts
	resp.Total = total

	response.CommonResp(ctx, 0, "查询成功", resp)
}

func DeletePost(ctx *gin.Context) {
	// 从请求体中解析 PostID
	var req struct {
		PostID int `json:"postID" binding:"required"`
	}

	if err := ctx.ShouldBindJSON(&req); err != nil || req.PostID <= 0 {
		response.CommonResp(ctx, 1, "无效的帖子 ID", nil)
		return
	}

	// 获取当前用户 ID 和角色
	userID, userExists := ctx.Get("userID")
	if !userExists {
		response.CommonResp(ctx, 1, "无法获取用户信息，请重新登录", nil)
		return
	}

	// 查找帖子
	var post models.Post
	if err := global.Db.First(&post, req.PostID).Error; err != nil {
		response.CommonResp(ctx, 1, "帖子不存在", nil)
		return
	}
	role, ok := ctx.Get("role")
	if !ok {
		response.CommonResp(ctx, 1, "无法获取用户信息，请重新登录", nil)
		return
	}
	if role != 0 && post.UserID != userID {
		// 检查权限，是自己的帖子
		response.CommonResp(ctx, 1, "无权限删除该帖子", nil)
		return
	}

	//// 删除文件资源（如果有）
	//if post.Video != "" {
	//	// 视频文件删除路径
	//	videoPath := filepath.Join("public", post.Video)
	//	if err := utils.DeleteFile(videoPath); err != nil {
	//		response.CommonResp(ctx, 1, "删除视频文件失败", nil)
	//		return
	//	}
	//}
	//待用
	//if post.Cover != "" {
	//	// 图片文件删除路径
	//	coverPath := filepath.Join("public", post.Cover)
	//	if err := utils.DeleteFile(coverPath); err != nil {
	//		response.CommonResp(ctx, 1, "删除封面文件失败", nil)
	//		return
	//	}
	//}

	// 执行软删除
	if err := global.Db.Delete(&post).Error; err != nil {
		response.CommonResp(ctx, 1, "删除帖子失败", nil)
		return
	}

	// 返回成功响应
	response.CommonResp(ctx, 0, "删除帖子成功", nil)
}

func GetPostDetail(ctx *gin.Context) {
	var resp = struct {
		Post response.RespPost `json:"post"`
	}{}

	// 获取请求参数
	postID := ctx.Query("postID")
	tokenString := ctx.Query("token")

	// 校验 postID 参数
	if postID == "" {
		response.CommonResp(ctx, 1, "缺少 postID 参数", nil)
		return
	}

	// 转换 postID 为整数
	postIDInt, err := strconv.Atoi(postID)
	if err != nil {
		response.CommonResp(ctx, 1, "postID 参数无效", nil)
		return
	}

	// 查询帖子
	var post models.Post
	query := global.Db.Unscoped().Model(&models.Post{}).Where("id = ?", postIDInt).Preload("User").First(&post)

	if err := query.Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			response.CommonResp(ctx, 1, "帖子不存在", nil)
		} else {
			response.CommonResp(ctx, 1, "查询失败", nil)
		}
		return
	}

	// 如果没有 token 或者 token 无效，则只能查看已审批的帖子
	token, err := utils.ParseString2Token(tokenString)
	if tokenString == "" || token == nil || !token.Valid {
		if post.IsAudit != 1 || post.DeletedAt.Valid { // 未审核或审核不通过的帖子不允许游客查看
			response.CommonResp(ctx, 1, "帖子未审批或审核未通过", nil)
			return
		}
	} else if post.IsAudit != 1 || post.DeletedAt.Valid {
		// 验证用户身份
		claims, ok := token.Claims.(jwt.MapClaims)
		userIDF, idOk := claims["ID"].(float64)
		roleF, roleOk := claims["role"].(float64)
		if !(ok && idOk && roleOk) {
			response.CommonResp(ctx, 1, "无效的 token", nil)
			return
		}
		userID := int(userIDF)
		role := int(roleF)

		if role != 0 {
			if post.UserID != userID {
				response.CommonResp(ctx, 1, "无权限查看该帖子", nil)
				return
			}
		}
	}

	// 返回帖子详情
	resp.Post = response.ToResponsePost(post)
	response.CommonResp(ctx, 0, "查询成功", resp)
}

// 获取删除的帖子记录
func GetDeletedPosts(ctx *gin.Context) {
	var req struct {
		PageNum     int    `json:"pageNum" binding:"required"`
		PageSize    int    `json:"pageSize" binding:"required"`
		SearchQuery string `json:"searchQuery"` // 非必填
	}

	var res struct {
		Posts []response.RespPost `json:"posts"`
		Total int64               `json:"total"`
	}

	if err := ctx.ShouldBindJSON(&req); err != nil {
		response.CommonResp(ctx, 1, "请求参数错误", nil)
		return
	}

	userID, exists := ctx.Get("userID")
	if !exists {
		response.CommonResp(ctx, 1, "用户未登录", nil)
		return
	}

	offset := (req.PageNum - 1) * req.PageSize

	// 查询当前用户已删除的帖子
	query := global.Db.Unscoped().Model(&models.Post{}).Preload("User").
		Where("deleted_at IS NOT NULL AND user_id = ?", userID)

	//模糊查询
	if req.SearchQuery != "" {
		searchQuery := "%" + req.SearchQuery + "%"
		query = query.Where("title LIKE ? OR content LIKE ?", searchQuery, searchQuery)
	}

	var total int64
	if err := query.Count(&total).Error; err != nil {
		response.CommonResp(ctx, 1, "查询总记录数失败", nil)
		return
	}

	var posts []models.Post
	if err := query.Offset(offset).Limit(req.PageSize).Order("deleted_at DESC").Find(&posts).Error; err != nil {
		response.CommonResp(ctx, 1, "查询失败", nil)
		return
	}

	utils.CutPostContent(&posts)

	respPosts := []response.RespPost{}
	for i := range posts {
		respPosts = append(respPosts, response.ToResponsePost(posts[i]))
	}

	res.Posts = respPosts
	res.Total = total

	response.CommonResp(ctx, 0, "查询成功", res)
}
